package controller

import (
	"awesomeProject/lib"
	"database/sql"
	"fmt"
	"github.com/gin-gonic/gin"
	"log"
)

var (
	pool         *sql.DB
	connStr      = "postgres://postgres:zkw030813@101.43.168.188:5432/postgres?sslmode=disable"
	defaultPhoto = "http://pic4.zhimg.com/v2-2f09c24693527a6b4c53bbee671d352f_r.jpg"
)

func Login(r *gin.Context) {
	log.Println("login running")
	var loginReq lib.LoginRequest
	if err := r.ShouldBindJSON(&loginReq); err != nil {
		r.JSON(400, lib.LoginResponse{
			StatusMsg:  "failed",
			StatusCode: 0,
		})
	}
	username := loginReq.Username
	password := loginReq.Password
	fmt.Printf("username: %v, password: %v \n", username, password)
	user, err, statusCode := auth(username, password)
	resp := lib.LoginResponse{}
	if err != nil {
		r.JSON(200, lib.LoginResponse{
			StatusMsg:  "select fail",
			StatusCode: 0,
		})
		log.Println("auth fail", err)
		return
	}

	if statusCode != 2 {
		resp.StatusCode = 1
		resp.StatusMsg = "password or username invalid"
		r.JSON(200, resp)
		return
	}
	resp.User = user
	resp.StatusCode = 2 //success
	resp.StatusMsg = "auth successfully"
	fmt.Println(resp)
	r.JSON(200, resp)
}

func InitAuth() error {
	var err error
	pool, err = sql.Open("postgres", connStr)
	if err != nil {
		log.Fatalln("fail to connect to postgres", err)
		return err
	}
	return nil
}

func auth(username string, password string) (lib.User, error, int) {
	passwordRef := ""
	user := lib.User{}
	row := pool.QueryRow("select password, photo, qq, birthday, id, gender from public.user where username=$1", username)
	err := row.Scan(&passwordRef, &user.Photo, &user.Qq, &user.Birthday, &user.Id, &user.Gender)
	if err != nil {
		log.Println("username invalid in auth ", err)
		return user, err, 0 //"username invalid"
	}
	fmt.Println(user)
	if password != passwordRef {
		return user, nil, 1 //"password or username is wrong"
	}
	user.Username = username
	return user, nil, 2 //"auth successfully"
}

func AuthId(id int64, password string) (bool, error) {
	var passwordRef string
	row := pool.QueryRow("select password from public.user where id=$1", id)
	if err := row.Scan(&passwordRef); err != nil {
		log.Println("authId fail for id invalid")
		return false, err
	}
	if passwordRef == password {
		return true, nil
	} else {
		return false, nil
	}

}

func Register(r *gin.Context) {
	log.Println("register running")
	var registerReq lib.RegisterRequest
	if err := r.ShouldBindJSON(&registerReq); err != nil {
		r.JSON(200, lib.RegisterResponse{
			StatusMsg:  "read json fail at register",
			StatusCode: 0,
		})
		log.Println("auth fail", err)
		return
	}
	username := registerReq.Username
	password := registerReq.Password
	_, ok, err := SearchUsername(username)
	if err != nil {
		r.JSON(200, lib.RegisterResponse{
			StatusMsg:  "database select fail",
			StatusCode: 0,
		})
		log.Println("failed to search username in register")
		return
	}
	if !ok {
		user, err := insertUser(lib.User{
			Username: username,
			Password: password,
			Photo:    defaultPhoto,
			Gender:   2,
			Qq:       "null",
			Email:    "null",
			Birthday: "2003-08-13",
		})
		if err != nil {
			log.Println("insert user fail in register")
			r.JSON(200, lib.RegisterResponse{
				StatusMsg:  "database insert fail",
				StatusCode: 0,
			})
			return
		}
		err = AddRelation(user.Id, 114514)
		err = AddRelation(user.Id, 1314520)
		err = AddRelation(user.Id, 9)
		err = AddRelation(user.Id, 10)
		err = AddRelation(user.Id, 10086)
		err = AddRelation(user.Id, 318030)

		registerResp := lib.RegisterResponse{
			User:       user,
			StatusCode: 2,
			StatusMsg:  "register successfully",
		}
		r.JSON(200, registerResp)
		welcome := lib.Message{
			Sender: lib.UserBrief{
				Id:       114514,
				Username: "xiwen",
				Photo:    defaultPhoto,
				Gender:   1,
			},
			Receiver: lib.UserBrief{Id: user.Id},
			Content: "欢迎来到小而美，这是一款简单轻量的即时聊天软件，我们的目标是教教张小龙做产品，你现在已经自动与全体开发人员以及我们的小美智能助手" +
				"添加成为好友，小美是我们接入chatgpt api的智能机器人，你可以自由地向她询问任何问题，除此之外，你还能通过好友列表访问公共聊天室，在那里可以" +
				"和在线的所有用户自由的聊天，你可以通过搜索好友以及添加好友按钮与你的小伙伴或者陌生人成为好友，也可以通过编辑个人信息按钮修改个人信息。" +
				"本项目是MacroSolid团队的c++大作业，团队成员分别是：张可为（xiwen），凌志（lingzhi），张泽远（zhangzeyuan），陈羿帆（chenyifan）",
			Type:    "chat",
			IsPhoto: 0,
		}
		if err := Chat(&welcome); err != nil {
			log.Println("send welcome to new user fail in register", err)
			return
		}
	} else {
		r.JSON(200, lib.RegisterResponse{
			StatusCode: 1,
			StatusMsg:  "username invalid",
		})
	}
	return
}

func SearchUsername(username string) (lib.User, bool, error) {
	var user lib.User
	row := pool.QueryRow("select id, username, photo, email, qq, gender, birthday from public.user where username=$1", username)
	err := row.Scan(&user.Id, &user.Username, &user.Photo, &user.Email, &user.Qq, &user.Gender, &user.Birthday)
	if err != nil {
		return user, false, nil
	}
	return user, true, nil
}

func SearchId(id int64) (lib.User, bool, error) {
	var user lib.User
	row := pool.QueryRow("select id, username, photo, email, qq, gender, birthday from public.user where id=$1", id)
	err := row.Scan(&user.Id, &user.Username, &user.Photo, &user.Email, &user.Qq, &user.Gender, &user.Birthday)
	if err != nil {
		return user, false, err
	}
	return user, true, nil
}

func SearchIdBrief(id int64) (lib.UserBrief, bool, error) {
	var user lib.UserBrief
	row := pool.QueryRow("select id, username, photo, gender from public.user where id=$1", id)
	err := row.Scan(&user.Id, &user.Username, &user.Photo, &user.Gender)
	if err != nil {
		return user, false, err
	}
	return user, true, nil
}

func insertUser(user lib.User) (lib.User, error) {
	err := pool.QueryRow("insert into public.user(username, photo, password, email, qq, gender, birthday) values ($1, $2, $3, $4, $5, $6, $7) returning id",
		user.Username,
		user.Photo,
		user.Password,
		user.Email, user.Qq,
		user.Gender,
		user.Birthday,
	).Scan(&user.Id) //操作数据库的方法本质上都是执行一段sql语句后返回一些东西，灵活利用不同方法的特性，如query方法就只要求有返回结果， 那么就可以运用到需要returning id的地方
	if err != nil {
		log.Println("queryrow fail in insertuser", err)
		return user, err
	}
	return user, nil
}
